package com.gzc.just.play.last.war.sceneserver.damage;

import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.DisplayName;

import static org.junit.jupiter.api.Assertions.*;

/**
 * DamageResult 单元测试 - 测试伤害结果类的核心功能
 * 覆盖伤害结果的创建、属性访问和序列化功能
 */
@DisplayName("伤害结果单元测试")
class DamageResultTest {

    private DamageResult damageResult;
    private long attackerId;
    private long defenderId;
    private int baseDamage;
    private int finalDamage;
    private DamageType damageType;

    @BeforeEach
    void setUp() {
        attackerId = 1001L;
        defenderId = 2002L;
        baseDamage = 100;
        finalDamage = 150;
        damageType = DamageType.PHYSICAL;

        damageResult = new DamageResult(attackerId, defenderId, finalDamage, damageType);
    }

    // ========== 基础创建 ==========

    @Test
    @DisplayName("测试1: 基础伤害结果创建")
    void testDamageResultCreation() {
        assertNotNull(damageResult);
        assertEquals(attackerId, damageResult.getAttackerId());
        assertEquals(defenderId, damageResult.getDefenderId());
        assertEquals(finalDamage, damageResult.getFinalDamage());
        assertEquals(damageType, damageResult.getDamageType());
        assertTrue(damageResult.getTimestamp() > 0);
    }

    @Test
    @DisplayName("测试2: 全参数伤害结果创建")
    void testFullParameterDamageResultCreation() {
        int damageAfterBonus = 120;
        int damageAfterDefense = 110;
        boolean isCritical = true;
        float criticalMultiplier = 2.0f;
        boolean isLethal = false;
        boolean isDodged = false;
        boolean isResisted = false;
        String damageReason = "普通攻击";

        DamageResult fullResult = new DamageResult(
                attackerId, defenderId, baseDamage, damageAfterBonus,
                damageAfterDefense, finalDamage, damageType, isCritical,
                criticalMultiplier, isLethal, isDodged, isResisted,
                System.currentTimeMillis(), damageReason
        );

        assertEquals(attackerId, fullResult.getAttackerId());
        assertEquals(defenderId, fullResult.getDefenderId());
        assertEquals(baseDamage, fullResult.getBaseDamage());
        assertEquals(damageAfterBonus, fullResult.getDamageAfterBonus());
        assertEquals(damageAfterDefense, fullResult.getDamageAfterDefense());
        assertEquals(finalDamage, fullResult.getFinalDamage());
        assertEquals(damageType, fullResult.getDamageType());
        assertTrue(fullResult.isCritical());
        assertEquals(criticalMultiplier, fullResult.getCriticalMultiplier(), 0.01f);
        assertFalse(fullResult.isLethal());
        assertFalse(fullResult.isDodged());
        assertFalse(fullResult.isResisted());
        assertEquals(damageReason, fullResult.getDamageReason());
    }

    // ========== 伤害类型测试 ==========

    @Test
    @DisplayName("测试3: 不同伤害类型")
    void testDifferentDamageTypes() {
        // 物理伤害
        DamageResult physicalResult = new DamageResult(attackerId, defenderId, 100, DamageType.PHYSICAL);
        assertEquals(DamageType.PHYSICAL, physicalResult.getDamageType());

        // 魔法伤害
        DamageResult magicalResult = new DamageResult(attackerId, defenderId, 100, DamageType.MAGICAL);
        assertEquals(DamageType.MAGICAL, magicalResult.getDamageType());

        // 纯伤害
        DamageResult pureResult = new DamageResult(attackerId, defenderId, 100, DamageType.PURE);
        assertEquals(DamageType.PURE, pureResult.getDamageType());

        // 真实伤害
        DamageResult trueResult = new DamageResult(attackerId, defenderId, 100, DamageType.TRUE_DAMAGE);
        assertEquals(DamageType.TRUE_DAMAGE, trueResult.getDamageType());
    }

    // ========== 暴击测试 ==========

    @Test
    @DisplayName("测试4: 暴击伤害结果")
    void testCriticalDamageResult() {
        // 创建暴击伤害结果
        DamageResult criticalResult = new DamageResult(
                attackerId, defenderId, baseDamage, 120, 110, 220,
                DamageType.PHYSICAL, true, 2.0f, false, false, false,
                System.currentTimeMillis(), "暴击攻击"
        );

        assertTrue(criticalResult.isCritical());
        assertEquals(2.0f, criticalResult.getCriticalMultiplier(), 0.01f);
        assertEquals(220, criticalResult.getFinalDamage());
    }

    @Test
    @DisplayName("测试5: 非暴击伤害结果")
    void testNonCriticalDamageResult() {
        // 创建非暴击伤害结果
        DamageResult nonCriticalResult = new DamageResult(
                attackerId, defenderId, baseDamage, baseDamage, baseDamage, finalDamage,
                DamageType.PHYSICAL, false, 1.0f, false, false, false,
                System.currentTimeMillis(), "普通攻击"
        );

        assertFalse(nonCriticalResult.isCritical());
        assertEquals(1.0f, nonCriticalResult.getCriticalMultiplier(), 0.01f);
    }

    // ========== 躲避与抵抗测试 ==========

    @Test
    @DisplayName("测试6: 躲避伤害结果")
    void testDodgedDamageResult() {
        // 创建躲避伤害结果
        DamageResult dodgedResult = new DamageResult(
                attackerId, defenderId, baseDamage, 0, 0, 0,
                DamageType.PHYSICAL, false, 1.0f, false, true, false,
                System.currentTimeMillis(), "躲避"
        );

        assertTrue(dodgedResult.isDodged());
        assertEquals(0, dodgedResult.getFinalDamage());
        assertEquals("躲避", dodgedResult.getDamageReason());
    }

    @Test
    @DisplayName("测试7: 抵抗伤害结果")
    void testResistedDamageResult() {
        // 创建抵抗伤害结果
        DamageResult resistedResult = new DamageResult(
                attackerId, defenderId, baseDamage, 50, 25, 25,
                DamageType.MAGICAL, false, 1.0f, false, false, true,
                System.currentTimeMillis(), "魔法抵抗"
        );

        assertTrue(resistedResult.isResisted());
        assertEquals(25, resistedResult.getFinalDamage());
        assertEquals("魔法抵抗", resistedResult.getDamageReason());
    }

    // ========== 致命一击测试 ==========

    @Test
    @DisplayName("测试8: 致命一击结果")
    void testLethalDamageResult() {
        // 创建致命一击伤害结果
        DamageResult lethalResult = new DamageResult(
                attackerId, defenderId, baseDamage, baseDamage, baseDamage, finalDamage,
                DamageType.PHYSICAL, false, 1.0f, true, false, false,
                System.currentTimeMillis(), "致命一击"
        );

        assertTrue(lethalResult.isLethal());
        assertEquals("致命一击", lethalResult.getDamageReason());
    }

    // ========== 伤害计算测试 ==========

    @Test
    @DisplayName("测试9: 伤害计算过程")
    void testDamageCalculationProcess() {
        // 基础伤害100，攻击加成20%，防御减少30%
        int baseDamage = 100;
        int damageAfterBonus = 120;  // 100 * 1.2
        int damageAfterDefense = 84;  // 120 * (1 - 0.3)
        int finalDamage = 84;

        DamageResult calculatedResult = new DamageResult(
                attackerId, defenderId, baseDamage, damageAfterBonus,
                damageAfterDefense, finalDamage, DamageType.PHYSICAL, false, 1.0f,
                false, false, false, System.currentTimeMillis(), "伤害计算测试"
        );

        assertEquals(baseDamage, calculatedResult.getBaseDamage());
        assertEquals(damageAfterBonus, calculatedResult.getDamageAfterBonus());
        assertEquals(damageAfterDefense, calculatedResult.getDamageAfterDefense());
        assertEquals(finalDamage, calculatedResult.getFinalDamage());
    }

    // ========== 时间戳测试 ==========

    @Test
    @DisplayName("测试10: 伤害结果时间戳")
    void testDamageResultTimestamp() {
        long beforeTimestamp = System.currentTimeMillis();
        
        DamageResult resultWithTimestamp = new DamageResult(attackerId, defenderId, finalDamage, damageType);
        
        long afterTimestamp = System.currentTimeMillis();
        
        assertTrue(resultWithTimestamp.getTimestamp() >= beforeTimestamp);
        assertTrue(resultWithTimestamp.getTimestamp() <= afterTimestamp);
        
        // 手动设置时间戳
        long customTimestamp = 1234567890L;
        damageResult.setTimestamp(customTimestamp);
        assertEquals(customTimestamp, damageResult.getTimestamp());
    }

    // ========== 伤害原因测试 ==========

    @Test
    @DisplayName("测试11: 伤害原因")
    void testDamageReason() {
        String skillName = "火球术";
        
        DamageResult skillDamageResult = new DamageResult(
                attackerId, defenderId, 80, 80, 80, 80,
                DamageType.MAGICAL, false, 1.0f, false, false, false,
                System.currentTimeMillis(), skillName
        );
        
        assertEquals(skillName, skillDamageResult.getDamageReason());
        
        // 更新伤害原因
        String newReason = "火焰爆裂";
        skillDamageResult.setDamageReason(newReason);
        assertEquals(newReason, skillDamageResult.getDamageReason());
    }

    // ========== 边界情况测试 ==========

    @Test
    @DisplayName("测试12: 零伤害结果")
    void testZeroDamageResult() {
        DamageResult zeroDamageResult = new DamageResult(attackerId, defenderId, 0, damageType);
        
        assertEquals(0, zeroDamageResult.getFinalDamage());
        assertEquals(0, zeroDamageResult.getBaseDamage());
        assertEquals(0, zeroDamageResult.getDamageAfterBonus());
        assertEquals(0, zeroDamageResult.getDamageAfterDefense());
    }

    @Test
    @DisplayName("测试13: 负伤害结果（治疗）")
    void testNegativeDamageResult() {
        int healAmount = -50;
        DamageResult healResult = new DamageResult(attackerId, defenderId, healAmount, DamageType.HEAL);
        
        assertEquals(healAmount, healResult.getFinalDamage());
        assertEquals(DamageType.HEAL, healResult.getDamageType());
    }

    @Test
    @DisplayName("测试14: 极高伤害结果")
    void testHighDamageResult() {
        int extremeDamage = 999999;
        DamageResult extremeResult = new DamageResult(attackerId, defenderId, extremeDamage, damageType);
        
        assertEquals(extremeDamage, extremeResult.getFinalDamage());
        assertEquals(extremeDamage, extremeResult.getBaseDamage());
    }

    // ========== 伤害结果序列化测试 ==========

    @Test
    @DisplayName("测试15: 伤害结果序列化")
    void testDamageResultSerialization() {
        // 创建一个完整的伤害结果
        DamageResult fullResult = new DamageResult(
                attackerId, defenderId, baseDamage, 120, 100, finalDamage,
                DamageType.PHYSICAL, true, 1.5f, false, false, false,
                System.currentTimeMillis(), "测试攻击"
        );

        // 转换为字符串（模拟序列化）
        String resultString = fullResult.toString();
        assertNotNull(resultString);
        assertFalse(resultString.isEmpty());
        
        // 验证字符串包含关键信息
        assertTrue(resultString.contains(String.valueOf(attackerId)));
        assertTrue(resultString.contains(String.valueOf(defenderId)));
        assertTrue(resultString.contains(String.valueOf(finalDamage)));
        // 使用getName()方法获取枚举的显示名称
        assertTrue(resultString.contains(damageType.getName()));
    }
}